#include <iostream>
#include <string>
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>

typedef websocketpp::server<websocketpp::config::asio> wsserver_t;

void http_callback(wsserver_t* server, websocketpp::connection_hdl hdl) 
{
    wsserver_t::connection_ptr conn = server->get_con_from_hdl(hdl); // 获取连接对象
    websocketpp::http::parser::request req = conn->get_request(); // 获取HTTP请求对象

    // 服务器显示HTTP请求格式
    // 1. 请求行：请求方法 URI HTTP版本
    std::cout << req.get_method() << " " << req.get_uri() << " " << req.get_version() << std::endl;
    // 2. 请求报头：key-value
    websocketpp::http::parser::header_list headers = req.get_headers(); // map容器
    for (auto& header : headers) 
    {
        std::cout << header.first << ": " << header.second << std::endl; 
    }
    // 3. 空行
    std::cout << std::endl;
    // 4. 请求正文
    std::cout << conn->get_request_body() << std::endl;

    // 给客户端返回一个页面
    std::string body = "<html><body><h1>Hello World</h1></body></html>";
    conn->set_status(websocketpp::http::status_code::ok);
    conn->append_header("Content-Type", "text/html");
    conn->set_body(body);
}

void open_callback(wsserver_t* server, websocketpp::connection_hdl hdl) 
{
    std::cout << "websocket握手成功" << std::endl;
}

void close_callback(wsserver_t* server, websocketpp::connection_hdl hdl) 
{
    std::cout << "websocket连接断开" << std::endl;
}

void message_callback(wsserver_t* server, websocketpp::connection_hdl hdl, wsserver_t::message_ptr msg) 
{
    wsserver_t::connection_ptr conn = server->get_con_from_hdl(hdl); // 获取连接对象
    std::cout << "client: " << msg->get_payload() << std::endl;
    std::string rsp = "I am fine, Thanks";
    conn->send(rsp, websocketpp::frame::opcode::text);
}

int main()
{
    // 1. 实例化server对象
    wsserver_t server;

    // 2. 设置日志等级
    server.set_access_channels(websocketpp::log::alevel::none);

    // 3. 初始化asio调度器
    server.init_asio();
    
    // 4. 设置回调函数：相比于websocket中多传入了一个参数，但是通过bind函数依然能做到符合两个参数要求
    server.set_http_handler(std::bind(&http_callback, &server, std::placeholders::_1));
    server.set_open_handler(std::bind(&open_callback, &server, std::placeholders::_1));
    server.set_close_handler(std::bind(&close_callback, &server, std::placeholders::_1));
    server.set_message_handler(std::bind(&message_callback, &server, std::placeholders::_1, std::placeholders::_2));

    // 5. 设置地址重用并监听端口，注意：需要按照顺序
    server.set_reuse_addr(true);
    server.listen(8080);

    // 6. 开始获取新连接
    server.start_accept();

    // 7. 启动服务器
    server.run();

    return 0;
}